import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { unlink } from 'node:fs/promises';
import { join } from 'path';
import { transformWithEsbuild } from 'vite';
import { dynamicImport, winPath } from '../../utils/index';
import { routesTpl, runtimeTpl } from './to-tpl';

const getRoutes = (items: any, pid: any) => {
  let i = 0;
  const flat = (items: any, pid: any) => {
    let list: any = [];
    items.forEach((item: any) => {
      i++;
      const route = {
        ...item,
        path: item?.path,
        element: item?.element,
        id: `${i}`,
        pid: `${pid}`,
      };
      list.push(route);
      if (item?.children?.length) {
        list = list.concat(flat(item?.children, i));
      }
    });
    return list;
  };
  return flat(items, pid);
};

export default async (routes: Array<any> = [], projectRoot = process.cwd()) => {
  const base = winPath(join(projectRoot, './src/.qps/plugin-router'));

  if (!existsSync(base)) {
    mkdirSync(base, { recursive: true });
  }

  const routeFile = winPath(
    join(projectRoot, './src/.qps/plugin-router/routes.tsx'),
  );

  const runtimeFile = winPath(
    join(projectRoot, './src/.qps/plugin-router/runtime.tsx'),
  );

  const tempRouteFile = winPath(join(projectRoot, './src/.qps/temp-routes.js'));
  const routeConfig = winPath(join(projectRoot, './src/routes.tsx'));
  let cacheRoutes = [];

  if (Array.isArray(routes) && routes?.length) {
    cacheRoutes = getRoutes(routes, 0);
  } else if (existsSync(routeConfig)) {
    const routeConfigCode = readFileSync(routeConfig, { encoding: 'utf-8' });

    const buildResult = await transformWithEsbuild(routeConfigCode, 'routes', {
      format: 'esm',
      platform: 'browser',
      loader: 'tsx',
      jsx: 'transform',
    });
    writeFileSync(tempRouteFile, buildResult?.code);
    cacheRoutes = (await dynamicImport(tempRouteFile)).default;
  }

  const result = getRoutes(cacheRoutes || [], 0);
  routesTpl(result, routeFile);
  runtimeTpl(runtimeFile);

  if (existsSync(tempRouteFile)) {
    unlink(tempRouteFile);
  }
};
